package com.sky.sky_server.service.impl;

import java.time.LocalDateTime;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;

import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import com.alibaba.fastjson2.JSON;
import com.github.pagehelper.Page;
import com.github.pagehelper.PageHelper;
import com.sky.sky_common.context.BaseContext;
import com.sky.sky_pojo.dto.HistoryOrderVO;
import com.sky.sky_pojo.dto.OrderSearchVO;
import com.sky.sky_pojo.dto.OrderStatisticsVO;
import com.sky.sky_pojo.dto.OrderSubmitDTO;
import com.sky.sky_pojo.dto.OrderSubmitVO;
import com.sky.sky_pojo.dto.OrderVO;
import com.sky.sky_pojo.entity.AddressBook;
import com.sky.sky_pojo.entity.OrderDetail;
import com.sky.sky_pojo.entity.OrderQueryPage;
import com.sky.sky_pojo.entity.Orders;
import com.sky.sky_pojo.entity.PageResult;
import com.sky.sky_pojo.entity.ShoppingCart;
import com.sky.sky_server.mapper.AddressBookMapper;
import com.sky.sky_server.mapper.OrderDetailMapper;
import com.sky.sky_server.mapper.OrderMapper;
import com.sky.sky_server.mapper.ShoppingCartMapper;
import com.sky.sky_server.service.OrderService;
import com.sky.sky_server.websocket.WebSocketServer;

@Service
public class OrderServiceImpl implements OrderService{

    @Autowired
    private OrderMapper orderMapper;

    @Autowired
    private ShoppingCartMapper shoppingCartMapper;

    @Autowired
    private AddressBookMapper addressBookMapper;

    @Autowired
    private OrderDetailMapper orderDetailMapper;

    @Autowired
    private WebSocketServer webSocketServer;

    /**
     * 提交订单
     */
    @Override
    @Transactional
    public OrderSubmitVO submitOrder(OrderSubmitDTO orderSubmitDTO) {
        // 异常的业务逻辑：用户地址簿为空，用户购物车为空
        AddressBook addressBook = addressBookMapper.selectById(orderSubmitDTO.getAddressBookId());
        if (addressBook == null) {
            // todo 类似于这种在事务中抛出的异常，都统一抛出的时RuntimeException，可以优化为自定义异常，并全局捕捉，这样前端才能看到异常信息
            throw new RuntimeException("地址簿不存在");
        }

        Long userId = BaseContext.getCurrentId();
        ShoppingCart shoppingCart = new ShoppingCart();
        shoppingCart.setUserId(userId);
        // 根据用户id,查询购物车中的商品信息
        List<ShoppingCart> shoppingCartList = shoppingCartMapper.selectByDishIdOrSetmealId(shoppingCart);
        if (shoppingCartList == null || shoppingCartList.size() == 0) {
            throw new RuntimeException("购物车为空");
        }

        // 向订单表插入一条数据
        Orders order = new Orders();
        BeanUtils.copyProperties(orderSubmitDTO, order);
        // 设置所有 数据库中的非空字段
        order.setUserId(userId);
        order.setStatus(Orders.OrderStatus.PENDING_PAYMENT.getCode());
        order.setOrderTime(LocalDateTime.now());
        order.setPayMethod(Orders.PayMethod.WECHAT.getCode()); // todo 写死支付方式为微信
        order.setPayStatus(Orders.PayStatus.UNPAID.getCode());
        order.setNumber(String.valueOf(System.currentTimeMillis())); // 生成订单号
        // 转移地址簿中的信息到订单中
        order.setPhone(addressBook.getPhone());
        order.setConsignee(addressBook.getConsignee());

        // 插入订单表
        int res = orderMapper.insert(order);
        if (res <= 0) {
            throw new RuntimeException("订单创建失败");
        }

        // 向订单明细表插入多条数据,一条数据对应一个购物车中的商品
        List<OrderDetail> orderDetails = new ArrayList<>();
        for(ShoppingCart sc : shoppingCartList){
            OrderDetail orderDetail = new OrderDetail();
            BeanUtils.copyProperties(sc, orderDetail);
            orderDetail.setOrderId(order.getId()); // 设置订单id
            orderDetails.add(orderDetail);
            
        }
        orderDetailMapper.insertBatch(orderDetails);

        // 向购物车表删除多条数据
        shoppingCartMapper.clean(userId);

        // 封装返回数据
        OrderSubmitVO orderSubmitVO = new OrderSubmitVO();
        orderSubmitVO.setId(order.getId());
        orderSubmitVO.setOrderAmount(order.getAmount());
        orderSubmitVO.setOrderNumber(order.getNumber());
        orderSubmitVO.setOrderTime(order.getOrderTime());
        return orderSubmitVO;
    }

    /**
     * 根据id查询订单详情
     */
    @Override
    public OrderVO getOrderDetail(Long id) {
        Orders order = orderMapper.selectById(id);
        OrderVO orderVO = new OrderVO();
        BeanUtils.copyProperties(order, orderVO);

        List<Long> ids = new ArrayList<>();
        ids.add(id);
        List<OrderDetail> orderDetails = orderDetailMapper.selectByOrderIds(ids);
        if(orderDetails != null && orderDetails.size() > 0){
            orderVO.setOrderDetailList(orderDetails);
        }
        return orderVO;
    }


    /**
     * 获取历史订单列表historyOrders
     * @param orderQueryPage 订单查询条件对象，包含分页信息和查询条件
     * @return PageResult<OrderVO> 分页结果对象，包含订单列表和总记录数
     */
    @Deprecated
    public PageResult<OrderVO> historyOrders1(OrderQueryPage orderQueryPage) {
        // 使用PageHelper进行分页查询设置
        PageHelper.startPage(orderQueryPage.getPage(), orderQueryPage.getPageSize());

        // 设置当前用户ID到查询条件中
        orderQueryPage.setUserId(BaseContext.getCurrentId());
        // 根据查询条件获取订单列表
        List<Orders> orders = orderMapper.selectQueryPage(orderQueryPage);
        // 从订单列表中提取所有订单ID
        List<Long> orderIds = orders.stream().map(order -> order.getId()).collect(Collectors.toList());

        // 根据订单ID列表获取所有订单详情
        if(orderIds == null || orderIds.size() == 0){
            List<OrderVO> result = new ArrayList<>();
            return new PageResult<OrderVO>(0L, result);
        }
        // 先进行判空操作，避免查询时拼接SQL出错
        List<OrderDetail> orderDetails = orderDetailMapper.selectByOrderIds(orderIds);
        // 将订单详情按订单ID分组，便于后续关联
        Map<Long, List<OrderDetail>> orderDetailMap = orderDetails.stream().collect(Collectors.groupingBy(OrderDetail::getOrderId));

        // 创建订单VO列表
        List<OrderVO> orderVOS = new ArrayList<>();
        // 遍历订单列表，将订单信息转换为VO对象并关联订单详情
        for(Orders order : orders){
            OrderVO orderVO = new OrderVO();
            // 复制订单属性到VO对象
            BeanUtils.copyProperties(order, orderVO);
            // 设置订单详情
            orderVO.setOrderDetailList(orderDetailMap.get(order.getId()));
            // 添加到VO列表
            orderVOS.add(orderVO);
        }

        // 创建分页对象
        Page<OrderVO> page = (Page<OrderVO>) orderVOS;

        // 获取分页结果
        List<OrderVO> result = page.getResult();
        // 获取总记录数
        Long total = page.getTotal();
        // 关闭分页对象
        page.close();

        // 返回分页结果
        return new PageResult<>(total, result);
        
    }


    /**
     * 获取历史订单列表
     * @param orderQueryPage 订单查询条件对象，包含分页信息和查询条件
     * @return PageResult<OrderVO> 分页结果对象，包含订单列表和总记录数
     */
    @Override
    public PageResult<HistoryOrderVO> historyOrders(OrderQueryPage orderQueryPage) {
        // 使用PageHelper进行分页查询设置
        PageHelper.startPage(orderQueryPage.getPage(), orderQueryPage.getPageSize());

        // 设置当前用户ID到查询条件中
        orderQueryPage.setUserId(BaseContext.getCurrentId());
        // 根据查询条件获取订单列表，这个结果已经是分页后的了
        List<Orders> orders = orderMapper.selectQueryPage(orderQueryPage);
        
        // 根据订单ID列表获取所有订单详情
        if(orders == null || orders.size() == 0)
            return new PageResult<>(0L, new ArrayList<HistoryOrderVO>());

        Long total = ((Page<Orders>) orders).getTotal();

        // 从订单列表中提取所有订单ID
        List<Long> orderIds = orders.stream().map(order -> order.getId()).collect(Collectors.toList());
        // 先进行判空操作，避免查询时拼接SQL出错
        List<OrderDetail> orderDetails = orderDetailMapper.selectByOrderIds(orderIds);
        // 将订单详情按订单ID分组，便于后续关联
        Map<Long, List<OrderDetail>> orderDetailMap = orderDetails.stream().collect(Collectors.groupingBy(OrderDetail::getOrderId));

        // 创建订单VO列表
        List<HistoryOrderVO> historyOrderVOs = new ArrayList<>();
        // 遍历订单列表，将订单信息转换为VO对象并关联订单详情
        for(Orders order : orders){
            HistoryOrderVO historyOrderVO = new HistoryOrderVO();
            // 复制订单属性到VO对象
            BeanUtils.copyProperties(order, historyOrderVO);
            // 设置订单详情
            historyOrderVO.setOrderDetailList(orderDetailMap.get(order.getId()));
            // 添加到VO列表
            historyOrderVOs.add(historyOrderVO);
        }

        // 返回分页结果
        return new PageResult<>(total, historyOrderVOs);
        
    }

    /**
     * 客户催单
     */
    @Override
    public void reminderOrder(Long id) {
        Orders orderDB = orderMapper.selectById(id);
        if(orderDB == null){
            throw new RuntimeException("订单不存在");
        }
        // 只有在订单状态为"待接单和已接单"时，才能催单
        if(orderDB.getStatus() != Orders.OrderStatus.PENDING_RECEIVE.getCode() && orderDB.getStatus() != Orders.OrderStatus.RECEIVED.getCode()){
            throw new RuntimeException("订单状态不正确");
        }
        Map<String, Object> map = new HashMap<>();
        map.put("type", 2);
        map.put("orderId", id);
        map.put("content", orderDB.getNumber());
        
        String jsonObject = JSON.toJSONString(map);
        // 向客户端发送
        webSocketServer.sendToAllClient(jsonObject);

    }

    /**
     * 用户端取消订单
     */
    @Override
    public void cancelOrder(Long id) {
        
        Orders orderDB = orderMapper.selectById(id);
        if(orderDB == null){
            throw new RuntimeException("订单不存在");
        }

        Orders order = new Orders();
        order.setId(id);
        // 当订单是代付款，待接单，已接单这三种情况时，才可以取消，否则不行
        if(orderDB.getStatus() == Orders.OrderStatus.PENDING_PAYMENT.getCode()){
            order.setStatus(Orders.OrderStatus.CANCELLED.getCode());
        }
        else if(orderDB.getStatus() == Orders.OrderStatus.PENDING_RECEIVE.getCode() ||
            orderDB.getStatus() == Orders.OrderStatus.RECEIVED.getCode()
            ){
            // todo 不考虑订单已支付的情况,不退款直接取消，没实现微信的退款接口
            order.setStatus(Orders.OrderStatus.REFUNDED.getCode());
        }
        // 更新订单状态
        orderMapper.updateById(order);
    }

    /**
     * 再来一单
     */
    @Override
    @Transactional
    public int repetitionOrder(Long id) {
        Orders orderDB = orderMapper.selectById(id);
        if(orderDB == null){
            throw new RuntimeException("订单不存在");
        }

        // 创建新订单
        Orders newOrder = new Orders();
        newOrder.setId(null);
        newOrder.setUserId(orderDB.getUserId());
        newOrder.setStatus(Orders.OrderStatus.PENDING_PAYMENT.getCode());
        newOrder.setOrderTime(LocalDateTime.now());
        newOrder.setPayMethod(orderDB.getPayMethod());
        newOrder.setPayStatus(Orders.PayStatus.UNPAID.getCode());
        newOrder.setNumber(String.valueOf(System.currentTimeMillis()));
        newOrder.setPhone(orderDB.getPhone());
        newOrder.setConsignee(orderDB.getConsignee());

        OrderSubmitDTO orderSubmitDTO = new OrderSubmitDTO();
        BeanUtils.copyProperties(orderDB,orderSubmitDTO);
        BeanUtils.copyProperties(orderSubmitDTO,newOrder);

        // 插入订单
        int res = orderMapper.insert(newOrder);
        if(res == 0){
            throw new RuntimeException("订单创建失败");
        }

        // 插入订单详情
        List<OrderDetail> orderDetails = orderDetailMapper.selectByOrderIds(Arrays.asList(id));
        
        if(orderDetails != null){
            for (OrderDetail orderDetail : orderDetails) {
                orderDetail.setId(null);
                orderDetail.setOrderId(newOrder.getId());
            }
            orderDetailMapper.insertBatch(orderDetails);
        }
        return 1;
    }

    /**
     * 确认订单，商家接单
     */
    @Override
    public int confirmOrder(Long id) {
        Orders orderDB = orderMapper.selectById(id);
        if(orderDB == null){
            throw new RuntimeException("订单不存在");
        }
        if(orderDB.getStatus() != Orders.OrderStatus.PENDING_RECEIVE.getCode()){
            throw new RuntimeException("订单状态不正确");
        }
        Orders newOrder = Orders.builder().id(id).status(Orders.OrderStatus.RECEIVED.getCode()).build();

        return orderMapper.updateById(newOrder);
    }

    /**
     * 取消订单
     */
    @Override
    public int cancelOrderForAdmin(Long id, String cancelReason) {
        Orders orderDB = orderMapper.selectById(id);
        if(orderDB == null){
            throw new RuntimeException("订单不存在");
        }
        // todo 真实情况是这里需要判断订单状况，并根据状况选择是否退款。这里不做判断直接取消

        if(orderDB.getStatus() >= Orders.OrderStatus.COMPLETED.getCode()){
            throw new RuntimeException("订单状态不正确, 无法取消");
        }

        Orders newOrder = Orders.builder().id(id).status(Orders.OrderStatus.CANCELLED.getCode()).cancelReason(cancelReason).build();

        return orderMapper.updateById(newOrder);
    }

    /**
     * 管理员查询订单
     */
    @Override
    public PageResult<OrderSearchVO> searchOrderForAdmin(OrderQueryPage orderQueryPage) {
        // todo 这里也可以通过自定义结果集的形式实现，但是感觉有点麻烦，这里先不做实现

        PageHelper.startPage(orderQueryPage.getPage(), orderQueryPage.getPageSize());

        List<Orders> res = orderMapper.selectQueryPage(orderQueryPage);
        Long total = ((Page<Orders>)res).getTotal();

        List<OrderSearchVO> orderSearchVOs = new ArrayList<>();
        // 订单包含的菜品列表
        for(Orders order : res){
            List<String> orderDishList = orderMapper.getOrderContainsDishList(order.getId());
            if(orderDishList != null){
                String dishListStr = orderDishList.stream().collect(Collectors.joining(","));
                OrderSearchVO orderSearchVO = new OrderSearchVO();
                BeanUtils.copyProperties(order, orderSearchVO);
                orderSearchVO.setOrderDishes(dishListStr);
                orderSearchVOs.add(orderSearchVO);
            }
        }

        return new PageResult<>(total, orderSearchVOs);
        
    }

    /**
     * 各个状态的订单数量
     */
    @Override
    public OrderStatisticsVO statisticsOrder() {
        return orderMapper.statisticsOrder();
    }

    /**
     * 管理员拒绝订单
     */
    @Override
    public int rejectOrderForAdmin(Long id, String cancelReason) {
        Orders order = orderMapper.selectById(id);
        if(order == null){
            throw new RuntimeException("订单不存在");
        }
        // 只有待接单状态才能拒单
        if(order.getStatus() != Orders.OrderStatus.PENDING_RECEIVE.getCode()){
            throw new RuntimeException("只有待接单状态才能拒单");
        }
        // todo 真实情况是这里需要判断订单状况，并根据状况选择是否退款。这里不做判断直接取消
        Orders newOrder = new Orders();
        newOrder.setId(id);
        newOrder.setStatus(Orders.OrderStatus.CANCELLED.getCode());
        newOrder.setCancelReason(cancelReason);

        return orderMapper.updateById(newOrder);

    }

    /**
     * 派送订单
     */
    @Override
    public int deliveryOrderForAdmin(Long id) {
        Orders order = orderMapper.selectById(id);
        if(order == null){
            throw new RuntimeException("订单不存在");
        }
        // 只有已接单状态才能派送
        if(order.getStatus() != Orders.OrderStatus.RECEIVED.getCode()){
            throw new RuntimeException("只有已接单状态才能派送");
        }

        Orders newOrder = new Orders();
        newOrder.setId(id);
        newOrder.setStatus(Orders.OrderStatus.DELIVERING.getCode());

        return orderMapper.updateById(newOrder);
    }

    /**
     * 确认订单完成
     */
    @Override
    public int completeOrderForAdmin(Long id) {
        Orders order = orderMapper.selectById(id);
        if(order == null){
            throw new RuntimeException("订单不存在");
        }
        // 只有派送中状态才能确认完成
        if(order.getStatus() != Orders.OrderStatus.DELIVERING.getCode()){
            throw new RuntimeException("只有派送中状态才能确认完成");
        }

        Orders newOrder = new Orders();
        newOrder.setId(id);
        newOrder.setStatus(Orders.OrderStatus.COMPLETED.getCode());

        return orderMapper.updateById(newOrder);
    }
}
